package com.free.semantic.common;


import java.util.List;
import java.util.Objects;

public class Range implements Comparable<Range> {

    public static Range ONE = new Range(1, 1, true, true);

    public static Range LESS_ONE = new Range(0, 1, true, true);

    public static Range MULTIPLE = new Range(0, null, true, false);

    public static Range MORE_ONE = new Range(1, null, true, false);

    public Integer getStart() {
        return start;
    }

    public boolean isIncludeStart() {
        return includeStart;
    }

    public Integer getEnd() {
        return end;
    }

    public boolean isIncludeEnd() {
        return includeEnd;
    }

    private Integer start;

    private boolean includeStart;

    private Integer end;

    private boolean includeEnd;

    public Range() {
    }

    public Range(Integer start, Integer end, boolean includeStart, boolean includeEnd) {
        this.start = start;
        this.end = end;
        this.includeStart = includeStart;
        this.includeEnd = includeEnd;
    }

    @Override
    public String toString() {
        if (this.equals(ONE)) {
            return "";
        }
        String res = "";
        if (includeStart) {
            res += "[";
        } else {
            res += "(";
        }
        res += start + ",";
        if (end != null) {
            res += end;
        }
        if (includeEnd) {
            res += "]";
        } else {
            res += ")";
        }
        return res;
    }

    public Range multi(Range range) {
        if (this.equals(ONE) && range.equals(ONE)) {
            return this;
        }
        int min = Math.min(this.start, range.start);
        if (min == 0) {
            return MULTIPLE;
        }
        return MORE_ONE;
    }

    public static Range multi(List<Range> rangeList) {
        Range result = Range.ONE;
        for (Range range : rangeList) {
            result = result.multi(range);
        }
        return result;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Range range = (Range) o;
        if (includeStart == range.includeStart && includeEnd == range.includeEnd && start.equals(range.start)) {
            if (end == null && range.end == null) {
                return true;
            }
            if (end == null || range.end == null) {
                return false;
            }
            return end.equals(range.end);
        }
        return false;
    }

    @Override
    public int hashCode() {
        return Objects.hash(start, includeStart, end, includeEnd);
    }

    @Override
    public int compareTo(Range rangeObj) {
        int thisEndTemp = this.end == null ? Integer.MAX_VALUE : this.end;
        int otherEndTemp = rangeObj.end == null ? Integer.MAX_VALUE : rangeObj.end;
        return thisEndTemp - otherEndTemp;
    }
}
